fi.foyt.svg.svgdom.FNISVGDOMUtils = {
  /**
   * Utility method to calculate on screen bounding box
   *
   * source is taken from
   *
   * http://the.fuchsia-design.com/2006/12/getting-svg-elementss-full-bounding-box.html
   *
   * @param {Object} element
   */
  getScreenBBox: function(element){
    /** get the complete transformation matrix **/
    
    var matrix = this.getTransformToElement(element, element.viewportElement);
    // get the bounding box of the target element
    var box = element.getBBox();
    // create an array of SVGPoints for each corner
    // of the bounding box and update their location
    // with the transform matrix
    var corners = [];
    var point = this._createSVGPoint(element, box.x, box.y);
    corners.push(point.matrixTransform(matrix));
    point.x = box.x + box.width;
    point.y = box.y;
    corners.push(point.matrixTransform(matrix));
    point.x = box.x + box.width;
    point.y = box.y + box.height;
    corners.push(point.matrixTransform(matrix));
    point.x = box.x;
    point.y = box.y + box.height;
    corners.push(point.matrixTransform(matrix));
    var max = this._createSVGPoint(element, corners[0].x, corners[0].y);
    var min = this._createSVGPoint(element, corners[0].x, corners[0].y);
    // identify the new corner coordinates of the
    // fully transformed bounding box
    for (var i = 1; i < corners.length; i++) {
      var x = corners[i].x;
      var y = corners[i].y;
      if (x < min.x) {
        min.x = x;
      } else if (x > max.x) {
        max.x = x;
      }
      if (y < min.y) {
        min.y = y;
      } else if (y > max.y) {
        max.y = y;
      }
    }
    // return the bounding box as an SVGRect object
    return this._createSVGRect(element, min.x, min.y, max.x - min.x, max.y - min.y);
  },
  /**
   * Returns screen bounding box for array of svg elements
   *
   * @param {Array} elements Array of elements
   * @return {SVGRect}
   */
  getElementSetScreenBBox: function(elements){
    try {
      if (!elements)
      return null;
    
    if (elements.length > 0) {
        var elementBBox = FNISVGDOMUtils.getScreenBBox(elements[0]);
        var minX = elementBBox.x;
        var minY = elementBBox.y;
        var maxX = elementBBox.x + elementBBox.width;
        var maxY = elementBBox.y + elementBBox.height;
        for (var i = 1; i < elements.length; i++) {
          elementBBox = FNISVGDOMUtils.getScreenBBox(elements[i]);
          minX = Math.min(minX, elementBBox.x);
          minY = Math.min(minY, elementBBox.y);
          maxX = Math.max(maxX, elementBBox.x + elementBBox.width);
          maxY = Math.max(maxY, elementBBox.y + elementBBox.height);
        }
    
    return this._createSVGRect(elements[0], minX, minY, maxX - minX, maxY - minY);
      }
      
    return null;
    } catch (e) {
      throw new Error("FNISVGDOMUtils::getElementSetScreenBBox: " + e);
    }
  },
  createElementFromJSON: function (svgDocument, aJSON) {
    var JSON = (Object.isString(aJSON)) ? aJSON.evalJSON() : aJSON;  
    
    var element = svgDocument.createElement(JSON.element);
    
    for (var i in JSON.attributes) 
      element.setAttribute(i, JSON.attributes[i]);
    
    return element;
  },
  removeIllegalAttributes: function (svgDocument, element) {
    var attributeNames = this.getElementAttributeNames(svgDocument, element);
    for (var i = 0; i < attributeNames.length; i++) {
      var attrName = attributeNames[i];
      var found = false;
      
      var attrs = this._LegalElementAttributes[element.tagName];
      
      var j = attrs.length;
      while ((j > 0) && (found == false)) {
        j--;
        if (attrs[j] == attrName) {
          found = true;
        }        
      }
       
      if (found == false)
        element.removeAttribute(attrName);
    }
  },
  getElementAttributeNames: function (svgDocument, element) {
    var attributeNames = new Array();
  
    for (var i = 0; i < element.attributes.length; i++)
      attributeNames.push(element.attributes[i].name);
    
    return attributeNames;
  },
  isValidSVGElement: function (element) {
    for (var i = 0; i < this._ValidSVGElements.length; i++) {
      if (this._ValidSVGElements[i] == element.tagName)
        return true;
    }
    return false;
  },
  /**
   * Private method to create SVGPoint object
   *
   * source is taken from
   *
   * http://the.fuchsia-design.com/2006/12/getting-svg-elementss-full-bounding-box.html
   *
   * @param {x} point x
   * @param {y} point y
   */
  _createSVGPoint: function(element, x, y){
    var point = element.viewportElement.createSVGPoint(); 
    point.x = x;
    point.y = y;
    return point;
  },
  /**
   * Private method to create SVGRect object
   *
   * source is taken from
   *
   * http://the.fuchsia-design.com/2006/12/getting-svg-elementss-full-bounding-box.html
   *
   * @param {x} rect x
   * @param {y} rect y
   * @param {width} rect width
   * @param {height} rect height
   */
  _createSVGRect: function(element, x, y, width, height){    
    var rect = element.viewportElement.createSVGRect();    
    rect.x = x;
    rect.y = y;
    rect.width = width;
    rect.height = height;
    return rect;
  },
  _LegalElementAttributes: {
    'rect': ['id','transform','style','x','y','rx','ry','width','height'],       
    'circle': ['id','transform','style','cx','cy','r'],
    'ellipse': ['id','transform','style','cx','cy','rx','ry'],
    'line': ['id','transform','style','x1', 'y1', 'x2', 'y2'],
    'polygon': ['id','transform','style','points'],
    'polyline': ['id','transform','style','points'],
    'path': ['id','transform','style','d'],
    'g': ['id','transform','style', 'fnigrouptype', 'fnilayertitle']
  },
  _ValidSVGElements: ['rect','circle','ellipse','line','polyline','polygon','path','g', 'defs', 'linearGradient', 'radialGradient', 'stop'],
  getTransformToElement: function (element, toElement) {
    return element.getTransformToElement(toElement);
  }
}; 